package org.hilo.boot.core.db;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 解析dataSourceLookupKey的策略
 * 可以实现对多slave数据源的读取策略，轮询、随机等。
 * 
 * @author zollty
 * @since 2018年6月6日
 */
public abstract class DataSourceLookupStrategy {
    private static final Logger logger = LoggerFactory.getLogger(DataSourceLookupStrategy.class);
    private Map<Object, ExtDataSource> dataSources;
    protected Map<Object, AtomicInteger> failureCount = new HashMap<Object, AtomicInteger>();

    /**
     * Retrieve the dataSourceKey identified by the given lookupKey.
     * 尽量做到线程安全
     * @param lookupKey the lookupKey
     * @return the dataSourceKey
     */
    abstract Object resolveSpecifiedLookupKey(Object lookupKey);
    
    /**
     * 标记失败的连接（失败多次可以禁用数据源）
     * <p>
     * 如果有多台 master 或者有多台 slave。多台master组成一个HA，要实现当其中一台master挂了是，
     * 自动切换到另一台master，这个功能可以使用LVS/Keepalived来实现，也可以通过这个类来实现，
     * 还可以另外加一个线程专门来每个一秒来测试mysql是否正常来实现。
     * 同样对于多台slave之间要实现负载均衡，同时当一台slave挂了时，要实现将其从负载均衡中去除掉，
     * 这个功能既可以使用LVS/Keepalived来实现，同样也可以通过这个类来实现。
     */
    public void markConnectionFailure(Object dataSourceKey) {
        AtomicInteger count = failureCount.get(dataSourceKey);
        if (count == null) {
            count = new AtomicInteger(1);
            failureCount.put(dataSourceKey, count);
        } else {
            logger.error("DB({}) connection failed {} times!",
                    dataSourceKey, count.getAndIncrement());
        }
    }

    public Map<Object, ExtDataSource> getDataSources() {
        return dataSources;
    }
    
    public void setDataSources(Map<Object, ExtDataSource> dataSources) {
        this.dataSources = dataSources;
    }

}
